/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.solution;

import java.io.Serializable;
import java.util.Observable;
import java.util.Observer;

import br.ufmg.dees.insane.assembler.Assembler;


/** 
 * A class defining a
 *
 * @author Fuina, Jamile & Pitangueira, Roque
 * @since March 2005
 */
public class EquilibriumPath extends Observable implements Solution, Observer, Serializable {
    
	private static final long serialVersionUID = 1L;
	private int numMaxSteps;    
    private Step step;
    private IteractiveStrategy[] iteracStrategy;
    protected double changeLoadFactor;
    protected double changeTolerance;
    protected int changeNumMaxIterations;
    
    private int currentStep;
    private String label;
    
    /* (non-Javadoc)
     * @see br.ufmg.dees.insane.solution.Solution#getLabel()
     */
    public String getLabel() {
        return label;
    }
    
    /* (non-Javadoc)
     * @see br.ufmg.dees.insane.solution.Solution#setLabel(java.lang.String)
     */
    public void setLabel(String label) {
        this.label = label;
    }
    
    /**
     * The constructor method
     */
    public EquilibriumPath() {
    }    
    
	/**
	 * The constructor method
	 * @param numMaxSteps the maximum number of steps
	 * @param numMaxIterations the maximum number of iteration
	 * @param loadFactor the specified first load factor
	 * @param tolerance the tolerance to check the convergence
	 */
	public EquilibriumPath(int numMaxSteps, Step sp, IteractiveStrategy[] is, double clf, double ctol, int cnmi) {
		this.numMaxSteps = numMaxSteps;
		this.step = sp;
		this.iteracStrategy = is;
		this.changeLoadFactor = clf;
		this.changeTolerance = ctol;
		this.changeNumMaxIterations = cnmi;
	}    

	/**
	 * @param changeNMI the new umber of maximum iteration
	 */
	public void setchangeNumMaxIterations(int changeNMI){
		changeNumMaxIterations = changeNMI;
	}		
	
	/**
	 * @return the current maximum number of iterations
	 */
	public int getchangeNumMaxIterations(){
	  return changeNumMaxIterations;
	}		
	
	public void setchangeTolerance(double changeTol){
	  	changeTolerance = changeTol;
	}		
	  
	public double getchangeTolerance(){
	  	 return changeTolerance;
	  }	

    public void setchangeLoadFactor(double changeLF){
  	 changeLoadFactor = changeLF;
  	}	
  
  	public double getchangeLoadFactor(){
  	
  	 return changeLoadFactor;
  	}	

  	public int getCurrentStep(){
    	 return currentStep;
    }
    
    /**
     * @return Returns the numMaxSteps.
     */
    public int getNumMaxSteps() {
        return numMaxSteps;
    }
    
    public void setNumMaxSteps(int numMS){
    	numMaxSteps = numMS;
    }
 
    public IteractiveStrategy[] getIteracStrategy() {
        return iteracStrategy;
    }
    
    public void setIteractiveStrategy(IteractiveStrategy[] itestr){
    	iteracStrategy = itestr;
    }
    
    public void setNumMaxInterations(int nmi){
    	this.step.setNumMaxIterations(nmi);
    }
	
    public void setTolerance(double tol){
    	this.step.setTolerance(tol);
    }

    public Step getStep(){
    	return step;
    }
    
    public void setStep(Step sp){
    	this.step = sp;
    }
    
    public void execute(){
    	int cont = 0;
    	currentStep = 1;
        step.getAssembler().init();
        step.addObserver(this);
    	step.setIteractiveStrategy(iteracStrategy[cont]);
    	do{
    	    iteracStrategy[cont].setStep(step);
    	    step.setLabel(this.currentStep);
    		step.execute();
    		if (!(step.getConvergence())){
    			if(cont < (iteracStrategy.length)-1){
                    cont++;
                    step.setIteractiveStrategy(iteracStrategy[cont]);
                }
//    			step.getIteractiveStrategy().setLoadFactor(this.changeLoadFactor);
    			step.setNumMaxIterations(this.changeNumMaxIterations);
    			step.setTolerance(this.changeTolerance);
    		}
    		else{
     			step.getAssembler().update();
    			currentStep++;
    		}
    	}
    	while(currentStep <= numMaxSteps);	
    }
    
    /* (non-Javadoc)
     * @see br.ufmg.dees.insane.solution.Solution#getAssembler()
     */
    public Assembler getAssembler() {
        return this.step.getAssembler();
    }

    /* (non-Javadoc)
     * @see br.ufmg.dees.insane.solution.Solution#setAssembler(br.ufmg.dees.insane.assembler.Assembler)
     */
    public void setAssembler(Assembler assembler) {
        this.step.setAssembler(assembler);
    }
    
    /* (non-Javadoc)
     * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    public void update(Observable o, Object arg) {
        this.hasChanged();
        this.setChanged();
        this.notifyObservers(this);
    }
    
    /** Gets the Unknow Dual Variables for this Assembler FemModel.<p>
     *@return The Ru vector of this Assembler FemModel.
     */
//    private void getRu(){
//    	LinearEquationSystems sel = new LinearEquationSystems();
//    	Assembler assembler = step.getAssembler();
//    	Iterator it = assembler.getModel().getLoadCombinationsList().iterator();
//        while (it.hasNext()){
//            LoadCombination lcomb = (LoadCombination)it.next();
//            System.out.println("Solving for Load Combination "+lcomb.getLabel());
//            sel.setAMatrix(assembler.getCpu());
//            sel.setXVector(assembler.getXu());
//            sel.solverB();
//            sel.subFromBVector(assembler.getEu());
//            sel.addToBVector(this.getCppXp());
//            // Subtracting possibles dual variables previously set.
//                sel.subFromBVector(assembler.getNu());
//                
//            assembler.setNu(sel.getBVector());
//	
//    }
//    }
    
//    /** Returns the Cpp*Xp for this Assembler FemModel.<p>
//	* The data is stored in the same order of equations.<br>
//	*Ex.: CppXp[0] is related to equation -1.
//	*@return The Cpp*Xp of this Assembler FemModel.
//	*/
/*	private IVector getCppXp()
	{
		Assembler assembler = step.getAssembler();
        IMatrix cpp = assembler.getCpp();
		IVector fed = new IVector (cpp.getNumRow());
		fed.mul(cpp, assembler.getXp());
		return (fed);
	}
*/
}
